﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;

namespace CFCEventReceiver
{
    public static class Utility
    {
        static Dictionary<string, Dictionary<string, Dictionary<string, SPRoleAssignment>>> UACConfig = new Dictionary<string, Dictionary<string, Dictionary<string, SPRoleAssignment>>>();
        static Dictionary<string, Dictionary<string, Dictionary<string, SPRoleDefinition>>> UACListConfig = new Dictionary<string, Dictionary<string, Dictionary<string, SPRoleDefinition>>>();

        public static SPListItem SetItemLevelPermission(this SPListItem listItem)
        {
            SPListItem item = listItem;
            Guid listId = listItem.ParentList.ID;
            Guid itemId = listItem.UniqueId;

            bool hasRoleDefine, hasListDefine = false;
            Dictionary<string, Dictionary<string, SPRoleAssignment>> roleConfig=null;
            Dictionary<string, Dictionary<string, SPRoleDefinition>> listConfig = null;

            hasRoleDefine=UACConfig.TryGetValue(item.Web.Name, out roleConfig);
            hasListDefine=UACListConfig.TryGetValue(item.Web.Name, out listConfig);
            if (!hasListDefine && !hasRoleDefine)
                return item;

            Dictionary<string, SPRoleAssignment> roleList=null;
            Dictionary<string, SPRoleDefinition> listList = null;
            if(hasRoleDefine)
                hasRoleDefine=roleConfig.TryGetValue(item.ParentList.Title, out roleList);
            if(hasListDefine)
                hasListDefine=listConfig.TryGetValue(item.ParentList.Title,out listList);
            if (!hasListDefine && !hasRoleDefine)
                return item;

            SPSecurity.RunWithElevatedPrivileges(
                delegate()
                {
                    SPUserToken token = item.Web.Site.SystemAccount.UserToken;
                    using (SPSite site = new SPSite(item.Web.Site.ID, token))
                    {
                        site.AllowUnsafeUpdates = true;
                        using (SPWeb web = site.OpenWeb(item.Web.ID))
                        {
                            web.AllowUnsafeUpdates = true;
                            var webApp = web.Site.WebApplication;
                            item = web.Lists[listId].Items[itemId];
                            SPRoleDefinition roleDefinition = web.RoleDefinitions.GetByType(SPRoleType.Contributor);
                            SPRoleAssignment roleAssignment;

                            SPPrincipal user = null;
                            user=GetPrincipal(item, "Author");
                            if (user == null)
                                return;
                            item.BreakRoleInheritance(false);
                            roleAssignment = new SPRoleAssignment(user);
                            roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
                            item.RoleAssignments.Add(roleAssignment);
                           
                            if (hasRoleDefine)
                            {
                                foreach (var gp in roleList.Values)
                                    item.RoleAssignments.Add(gp);
                            }
                           
                            if (hasListDefine)
                            {
                                foreach (var rd in listList)
                                {
                                    if (!item.Fields.ContainsField(rd.Key))
                                        continue;
                                    user = GetPrincipal(item, rd.Key);
                                    if (user == null)
                                        continue;
                                    roleAssignment = new SPRoleAssignment(user);
                                    roleAssignment.RoleDefinitionBindings.Add(rd.Value);
                                    item.RoleAssignments.Add(roleAssignment);

                                }
                            }
                            item.Update(); // call this function before finished 
                            web.AllowUnsafeUpdates = false;
                        }
                    }
                }
                );
            return item;
        }

        private static SPPrincipal GetPrincipal(SPListItem item,string fieldName)
        {
            var idStr = item[fieldName].ToString().Split(new char[] { ';' });
            int id = 0;
            if (int.TryParse(idStr[0], out id))
                return item.Web.SiteUsers.GetByID(id);
            else
                return null;
        }

        public static void CheckUACConfig(SPItemEventProperties properties)
        {
            if (UACConfig.Count == 0)
            {
                InitUACConfig(properties);
                return;
            }
            if (!string.Equals("UACConfig", properties.ListTitle, StringComparison.OrdinalIgnoreCase))
                return;
            SPListItem item = properties.ListItem;
            Guid listId = item.ParentList.ID;
            Guid itemId = item.UniqueId;

            SPSecurity.RunWithElevatedPrivileges(
                delegate()
                {
                    SPUserToken token = item.Web.Site.SystemAccount.UserToken;
                    using (SPSite site = new SPSite(item.Web.Site.ID, token))
                    {
                        using (SPWeb web = site.OpenWeb(item.Web.ID))
                        {

                            Dictionary<string, Dictionary<string, SPRoleAssignment>> listConfig;
                            if (!UACConfig.TryGetValue(web.Name, out listConfig))
                            {
                                listConfig = new Dictionary<string, Dictionary<string, SPRoleAssignment>>();
                                UACConfig.Add(web.Name, listConfig);
                            }
                            item = web.Lists[listId].Items[itemId];
                            string listName = item["ListName"].ToString();
                            Dictionary<string, SPRoleAssignment> groupList;
                            if (!listConfig.TryGetValue(listName, out groupList))
                            {
                                groupList = new Dictionary<string, SPRoleAssignment>();
                                listConfig.Add(listName, groupList);
                            }
                            groupList.Clear();

                            string groupStr = item["GroupName"].ToString();
                            string gpTemp;

                            foreach (var gp in groupStr.Split(new char[] { ',' }))
                            {
                                gpTemp = gp.Trim();
                                if (string.IsNullOrEmpty(gpTemp))
                                    continue;
                                try
                                {
                                    SPPrincipal group = web.Groups[gpTemp];
                                    var role = web.RoleAssignments.GetAssignmentByPrincipal(group);
                                    groupList[group.Name] = role;
                                }
                                catch
                                {

                                }
                            }
                        }
                    }
                });
        }

        private static void InitUACConfig(SPItemEventProperties properties)
        {
            UACConfig.Clear();
            SPListItem item = properties.ListItem;

            SPSecurity.RunWithElevatedPrivileges(
                delegate()
                {
                    SPUserToken token = item.Web.Site.SystemAccount.UserToken;
                    using (SPSite site = new SPSite(item.Web.Site.ID, token))
                    {
                        using (SPWeb web = site.OpenWeb(item.Web.ID))
                        {

                            SPList list = null;
                            try
                            {
                                list = web.Lists["UACConfig"];
                            }
                            catch { }
                            if (list == null)
                                return;
                            Dictionary<string, Dictionary<string, SPRoleAssignment>> listConfig = new Dictionary<string, Dictionary<string, SPRoleAssignment>>();
                            UACConfig.Add(properties.Web.Name, listConfig);

                            foreach (SPListItem listitem in list.Items)
                            {
                                string listName = listitem["ListName"].ToString();

                                Dictionary<string, SPRoleAssignment> groupList = new Dictionary<string, SPRoleAssignment>();

                                string groupStr = listitem["GroupName"].ToString();
                                string gpTemp;
                                foreach (var gp in groupStr.Split(new char[] { ',' }))
                                {
                                    try
                                    {
                                        gpTemp = gp.Trim();
                                        if (string.IsNullOrEmpty(gpTemp))
                                            continue;
                                        var group = web.Groups[gpTemp];

                                        var role = web.RoleAssignments.GetAssignmentByPrincipal(group);
                                        groupList[group.Name] = role;
                                    }
                                    catch
                                    {

                                    }
                                }
                                listConfig[listName] = groupList;
                            }
                        }
                    }
                });
        }

        public static void DelUACConfig(SPItemEventProperties properties)
        {
            if (string.Equals("UACConfig", properties.ListTitle, StringComparison.OrdinalIgnoreCase))
            {
                SPListItem item = properties.ListItem;
                Guid listId = item.ParentList.ID;
                Guid itemId = item.UniqueId;
                SPSecurity.RunWithElevatedPrivileges(
                delegate()
                {
                    SPUserToken token = item.Web.Site.SystemAccount.UserToken;
                    using (SPSite site = new SPSite(item.Web.Site.ID, token))
                    {
                        using (SPWeb web = site.OpenWeb(item.Web.ID))
                        {
                            item = web.Lists[listId].Items[itemId];
                            Dictionary<string, Dictionary<string, SPRoleAssignment>> listConfig;
                            if (UACConfig.TryGetValue(web.Name, out listConfig))
                            {
                                var listName = item["ListName"].ToString();
                                if (listConfig.ContainsKey(listName))
                                    listConfig.Remove(listName);
                            }
                        }
                    }
                });
            }
        }

        public static void CheckUACListConfig(SPItemEventProperties properties)
        {
            if (UACListConfig.Count == 0)
            {
                InitUACListConfig(properties);
                return;
            }
            if (!string.Equals("UACListConfig", properties.ListTitle, StringComparison.OrdinalIgnoreCase))
                return;
            SPListItem item = properties.ListItem;
            Guid listId = item.ParentList.ID;
            Guid itemId = item.UniqueId;

            SPSecurity.RunWithElevatedPrivileges(
                delegate()
                {
                    SPUserToken token = item.Web.Site.SystemAccount.UserToken;
                    using (SPSite site = new SPSite(item.Web.Site.ID, token))
                    {
                        using (SPWeb web = site.OpenWeb(item.Web.ID))
                        {
                            Dictionary<string, Dictionary<string, SPRoleDefinition>> listConfig;
                            if (!UACListConfig.TryGetValue(web.Name, out listConfig))
                            {
                                listConfig = new Dictionary<string, Dictionary<string, SPRoleDefinition>>();
                                UACListConfig.Add(web.Name, listConfig);
                            }
                            item = web.Lists[listId].Items[itemId];
                            string listName = item["ListName"].ToString();
                            Dictionary<string, SPRoleDefinition> groupList;
                            if (!listConfig.TryGetValue(listName, out groupList))
                            {
                                groupList = new Dictionary<string, SPRoleDefinition>();
                                listConfig.Add(listName, groupList);
                            }
                            groupList.Clear();

                            string userField = item["UserField"].ToString();
                           
                            var roleType=GetRoleType(item["RoleType"].ToString());
                             if (roleType == SPRoleType.None)
                                return;
                            SPRoleDefinition roleDefinition = web.RoleDefinitions.GetByType(roleType);
                           
                            groupList[userField] = roleDefinition;
                        }
                    }
                });

        }

        static SPRoleType GetRoleType(string type)
        {
            switch (type)
            {
                case "Guest":
                    return SPRoleType.Guest;
                case "Reader":
                    return SPRoleType.Reader;
                case "Contributor":
                    return SPRoleType.Contributor;
                case "WebDesigner":
                    return SPRoleType.WebDesigner;
                case "Administrator":
                    return SPRoleType.Administrator;
                default:
                    return SPRoleType.None;
            }
        }

        private static void InitUACListConfig(SPItemEventProperties properties)
        {
            UACListConfig.Clear();
            SPListItem item = properties.ListItem;

            SPSecurity.RunWithElevatedPrivileges(
                delegate()
                {
                    SPUserToken token = item.Web.Site.SystemAccount.UserToken;
                    using (SPSite site = new SPSite(item.Web.Site.ID, token))
                    {
                        using (SPWeb web = site.OpenWeb(item.Web.ID))
                        {

                            SPList list = null;
                            try
                            {
                                list = web.Lists["UACListConfig"];
                            }
                            catch { }
                            if (list == null)
                                return;
                            Dictionary<string, Dictionary<string, SPRoleDefinition>> listConfig = new Dictionary<string, Dictionary<string, SPRoleDefinition>>();
                            UACListConfig.Add(properties.Web.Name, listConfig);

                            foreach (SPListItem listitem in list.Items)
                            {
                                string listName = listitem["ListName"].ToString();

                                Dictionary<string, SPRoleDefinition> permissionList;
                                if (!listConfig.TryGetValue(listName, out permissionList))
                                {
                                    permissionList = new Dictionary<string, SPRoleDefinition>();
                                    listConfig[listName]= permissionList;
                                }

                                string userField = listitem["UserField"].ToString();
                                var roleType = GetRoleType(listitem["RoleType"].ToString());
                                if (roleType == SPRoleType.None)
                                    return;
                                SPRoleDefinition roleDefinition = web.RoleDefinitions.GetByType(roleType);
                                permissionList[userField] = roleDefinition;
                            }
                        }
                    }
                });
        }
        public static void DelUACListConfig(SPItemEventProperties properties)
        {
            if (string.Equals("UACListConfig", properties.ListTitle, StringComparison.OrdinalIgnoreCase))
            {
                SPListItem item = properties.ListItem;
                Guid listId = item.ParentList.ID;
                Guid itemId = item.UniqueId;
                SPSecurity.RunWithElevatedPrivileges(
                delegate()
                {
                    SPUserToken token = item.Web.Site.SystemAccount.UserToken;
                    using (SPSite site = new SPSite(item.Web.Site.ID, token))
                    {
                        using (SPWeb web = site.OpenWeb(item.Web.ID))
                        {
                            item = web.Lists[listId].Items[itemId];
                            Dictionary<string, Dictionary<string, SPRoleDefinition>> listConfig;
                            if (UACListConfig.TryGetValue(web.Name, out listConfig))
                            {
                                var listName = item["ListName"].ToString();
                                Dictionary<string, SPRoleDefinition> permission;
                                if (listConfig.TryGetValue(listName, out permission))
                                {
                                    var userField = item["UserField"].ToString();
                                    if (permission.ContainsKey(userField))
                                        permission.Remove(userField);
                                }
                            }
                        }
                    }
                });
            }
        }
    }
}
